<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Drag &amp; Drop in Mono Winforms</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="GUI, Mono, IronPython, drag &amp; drop, Winforms, tutorial, Linux, programming">
<meta name="description" content="Drag &amp; drop in Mono Winforms">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>

<div class="container">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<div class="content">

<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>Drag &amp; Drop in Mono Winforms</h1>


<p>
This part of the IronPython Mono Winforms tutorial
will be dedicated to the drag &amp; drop operations. 
</p>

<div class="center">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<p>
In computer graphical user interfaces, drag-and-drop is the action of 
(or support for the action of) clicking on a virtual object and 
dragging it to a different location or onto another virtual object. 
In general, it can be used to invoke many kinds of actions, or create various types 
of associations between two abstract objects. (Wikipedia)
</p>

<p>
Drag and drop functionality is one of the most visible aspects of the 
graphical user interface. Drag and drop operation enables you to do 
complex things intuitively. 
</p>


<h2>Dragging a button</h2>

<p>
In the first example, we will do the drag &amp; drop operation on the button control. 
The example does the job outside the drag &amp; drop protocol. 
</p>

<div class="codehead">dragbutton.py</div>
<pre class="code">
#!/usr/bin/ipy

import clr
clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")

from System.Windows.Forms import Application, Form, Button
from System.Drawing import Size, Point

class IForm(Form):

    def __init__(self):
        self.Text = 'Drag &amp; Drop'

        button = Button()
        button.Parent = self
        button.Text = 'Button'
        button.MouseDown += self.OnMousDown
        button.MouseUp += self.OnMousUp
        button.MouseMove += self.OnMousMove

        button.Location = Point(20, 20)

        self.isDragging = False
        self.CenterToScreen()

    def OnMousDown(self, sender,  event):
  
        self.isDragging = True
        self.oldX = event.X
        self.oldY = event.Y

    def OnMousMove(self, sender, event):
  
        if self.isDragging: 
            sender.Top = sender.Top + (event.Y - self.oldY)
            sender.Left = sender.Left + (event.X - self.oldX)
    

    def OnMousUp(self, sender,  event):
        self.isDragging = False
  

Application.Run(IForm())
</pre>


<p>
The code example puts a regular button control on the form container. 
By clicking on the button surface and simultaneously dragging it with
a mouse we can relocate the button. 
</p>

<p>
There are some supporting variables in our example. 
The <b class="keyword">isDragging</b> variable tells us, whether we are
in the process of dragging an object. The <b class="keyword">oldX</b> 
and <b class="keyword">oldY</b> variables
store the x, y coordinates just before the dragging process begins. 
</p>

<pre class="explanation">
 button.MouseDown += self.OnMousDown
 button.MouseUp += self.OnMousUp
 button.MouseMove += self.OnMousMove
</pre>

<p>
We plug in three different mouse handlers for our button. 
They implement three different stages of the drag &amp; drop process. 
The process begins, when we click on the button. This is handled by the
<b class="keyword">OnMousDown()</b> method. The second
part is the movement. This is when we move the object to a new position.
It is handled in the <b class="keyword">OnMousMove()</b> method.
The final part is when the process stops. It happens when we release 
the mouse button. The appropriate task is delegated to the
<b class="keyword">OnMousUp()</b> method.
</p>

<pre class="explanation">
 def OnMousDown(self, sender,  event):
  
    self.isDragging = True
    self.oldX = event.X
    self.oldY = event.Y
</pre>

<p>
The <b class="keyword">OnMousDown()</b> method implements the first 
part of the process. It sets three necessary variables. 
</p>


<pre class="explanation">
 def OnMousMove(self, sender, event):
  
     if self.isDragging: 
         sender.Top = sender.Top + (event.Y - self.oldY)
         sender.Left = sender.Left + (event.X - self.oldX)
</pre>

<p>
In the <b class="keyword">OnMousMove()</b> method, we relocate the button. 
We calculate the difference between the stored x, y coordinates and the 
new coordinates of the mouse pointer. The difference is added to the <b class="keyword">Top</b> and 
<b class="keyword">Left</b> properties of the button, thus moving it to a new position.
</p>


<br>
<img src="/img/gui/ironpython/dragbutton.png" alt="Dragging a button">
<div class="figure">Figure: Dragging a button</div>

<h2>Dragging Text</h2>

<p>
In the previous example, we did drag &amp; drop on the control. Next we will 
do a drag &amp; drop operation on the textual data. Here we will use the 
drag &amp; drop protocol provided by the Winforms library.
</p>

<p>
Drag &amp; drop operation is a standardized communication protocol in Winforms. 
We have two basic objects. The <b>drag source</b> and
the <b>drop target</b>.  
</p>

<div class="codehead">dragtext.py</div>
<pre class="code">
#!/usr/bin/ipy

import clr
clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")


from System.Windows.Forms import Application, Form, Button
from System.Windows.Forms import TextBox, DragDropEffects, DataFormats
from System.Drawing import Size, Point

class IForm(Form):

    def __init__(self):
        self.Text = 'Drag &amp; Drop'
        self.AllowDrop = True

        button = Button()
        button.Parent = self
        textBox = TextBox()
        textBox.Parent = self
 
        button.AllowDrop = True
        button.Location = Point(150, 50)
        button.DragDrop += self.OnDragDrop
        button.DragEnter += self.OnDragEnter

        textBox.Location = Point(15, 50)
        textBox.MouseDown += self.OnMousDown

        self.ClientSize = Size(250, 200)
        self.CenterToScreen()


    def OnMousDown(self, sender, event):
        sender.SelectAll()
        sender.DoDragDrop(sender.Text, DragDropEffects.Copy)
    

    def OnDragEnter(self, sender, event):
    
        if event.Data.GetDataPresent(DataFormats.Text):
            event.Effect = DragDropEffects.Copy
      

    def OnDragDrop(self, sender, event):
        sender.Text =  event.Data.GetData(DataFormats.Text)
    

Application.Run(IForm())
</pre>

<p>
We have two controls on the form. A button and a text box. We will drag text from the text box and
drop it on the button. 
</p>


<pre class="explanation">
 self.AllowDrop = True
</pre>

<p>
We set the <b class="keyword">AllowDrop</b> property to true. Dropping is not enabled by default. 
</p>

<pre class="explanation">
 button.DragDrop += self.OnDragDrop
 button.DragEnter += self.OnDragEnter
 ...       
 extBox.MouseDown += self.OnMousDown
</pre>

<p>
Again, the drag &amp; drop process is divided into three steps. We have 
three methods for each particular step. 
</p>

<pre class="explanation">
 def OnMousDown(self, sender, event):
     sender.SelectAll()
     sender.DoDragDrop(sender.Text, DragDropEffects.Copy)
</pre>

<p>
In the <b class="keyword">OnMousDown()</b> method we initialize the drap &amp; 
drop process. We initiate the process with the <b class="keyword">DoDragDrop()</b> 
method. The <b class="keyword">DragDropEffects.Copy</b>
parameter specifies the type of the operation. Esentially, we can either copy the 
text or move it during the drag &amp; drop operation. 
</p>

<pre class="explanation">
 def OnDragEnter(self, sender, event):
    
     if event.Data.GetDataPresent(DataFormats.Text):
         event.Effect = DragDropEffects.Copy

</pre>

<p>
The <b class="keyword">DragEnter</b> event is launched when the mouse 
pointer enters the area of the drop target control.
The <b class="keyword">Effect</b> property must be set. The 
DragDropEffects of the drag source and drop target must be equal.
Otherwise the operation will not work. 
</p>


<pre class="explanation">
 def OnDragDrop(self, sender, event):
     sender.Text =  event.Data.GetData(DataFormats.Text)
</pre>

<p>
Finally we have the <b class="keyword">OnDragDrop()</b> method. Here we get 
the data from the event object and
set it to the button <b class="keyword">Text</b> property.
</p>


<br>
<img src="/img/gui/ironpython/dragtext.png" alt="Drag &amp; drop of text">
<div class="figure">Figure: Drag &amp; drop of text</div>



<h2>Dragging Image</h2>

<p>
In our last example, we will drag &amp; drop image on the form. 
</p>


<div class="codehead">dragimage.py</div>
<pre class="code">
#!/usr/bin/ipy

import sys
import clr
clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")

from System.Windows.Forms import Application, Form, PictureBox, PictureBoxSizeMode
from System.Windows.Forms import Cursors
from System.Drawing import Size, Point, Rectangle, Brushes, Bitmap

class IForm(Form):

    def __init__(self):

        self.ClientSize = Size(350, 250)
        self.Text = "Dragging Images"
        self.Paint += self.OnPaint
    
        self.isDragging = False
        self.dropRect = Rectangle(10, 10, 200, 160)
        self.brush = Brushes.Gray
        picBox = PictureBox()

        self.loadImage()

        self.isDragging = False
        self.CenterToScreen()

        picBox.Parent = self
        picBox.Location = Point(100, 50)
        picBox.Size = Size(self.image.Width, self.image.Height)
        picBox.Image = self.image
        picBox.MouseDown += self.OnMousDown
        picBox.MouseUp += self.OnMousUp
        picBox.MouseMove += self.OnMousMove
        picBox.Cursor = Cursors.Hand


    def loadImage(self):
        try:
            self.image = Bitmap("image.jpg")
        except Exception, e: 
            print "Error reading image"
            print e.msg
            sys.exit(1)


    def OnMousMove(self, sender, event): 
        if self.isDragging:
            sender.Top = sender.Top + (event.Y - self.oldY)
            sender.Left = sender.Left + (event.X - self.oldX)


    def OnMousUp(self, sender, event):
        self.isDragging = False

        if self.dropRect.Contains(sender.Bounds):
            self.brush = Brushes.Gold
        else: 
            self.brush = Brushes.Gray

        self.Refresh()


    def OnMousDown(self, sender, event):
        self.isDragging = True
        self.oldX = event.X
        self.oldY = event.Y
 

    def OnPaint(self, event): 
        g = event.Graphics
        g.FillRectangle(self.brush, self.dropRect)
 
  
Application.Run(IForm()) 
</pre>

<p>
In our example we have a <b class="keyword">PictureBox</b> and we draw a gray rectangle. 
If we drop the picture inside the rectangle, the color of the rectangle changes to gold. 
</p>

<pre class="explanation">
 self.brush = Brushes.Gray
</pre>

<p>
The <b class="keyword">self.brush</b> variable holds the brush of the rectangle. 
It is a gray color by default.  
</p>

<pre class="explanation">
 def loadImage(self):
     try:
         self.image = Bitmap("image.jpg")
     except Exception, e: 
         print "Error reading image"
         print e.msg
         sys.exit(1)
</pre>

<p>
The <b class="keyword">loadImage()</b> method loads a bitmap 
for the <b class="keyword">PictureBox</b> control.
</p>

<pre class="explanation">
 if self.dropRect.Contains(sender.Bounds):
     self.brush = Brushes.Gold
 else: 
     self.brush = Brushes.Gray
</pre>

<p>
In the <b class="keyword">OnMousUp()</b> method, we determine the brush of 
the rectangle. If the bounds of the picture box are inside the rectangle, 
the brush is of gold color; gray otherwise.
</p>

<pre class="explanation">
 self.Refresh()
</pre>

<p>
We must call the <b class="keyword">Refresh()</b> method to activate the new brush color. 
</p>

<br>
<img src="/img/gui/ironpython/dragimage.png" alt="Drag &amp; drop image">
<div class="figure">Figure: Drag &amp; drop image</div>

<hr class="btm">

<p>
This chapter was dedicated to drag &amp; drop operations using the Mono Winforms library. 
</p>

<div class="center">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>
<br>

<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡ 
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified January 29, 2009  <span class="copyright">&copy; 2007 - 2012 Jan Bodnar</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>

